package com.chuangyi.config.client.impl;

import com.chuangyi.config.client.ConfigService;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.Watcher;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by fangtao on 2017/6/4.
 */
public class ZookeeperConfigService implements ConfigService {

    private Map<String, String> configMap = new ConcurrentHashMap<>();

    @Resource
    private CuratorFramework curatorFramework;

    private String application;

    @Override
    public void get(String key) {
        configMap.get(key);
    }

    @Override
    public void delete(String key) {

    }

    @Override
    public void put(String key, String value) {

    }

    @Override
    public Map<String, String> getAll() {
        return configMap;
    }

    public void init() throws Exception {
        curatorFramework.start();
        loadConfigs();
    }

    private void loadConfigs() throws Exception {
        List<String> configPaths = curatorFramework.getChildren().forPath(application);
        for (String path : configPaths) {
            initConfig(path);
        }
    }

    private void initConfig(String path) {
        String data = getAndWatch(path);
        configMap.put(path, data);
    }

    private String getAndWatch(String path) {
        try {
            byte[] bytes = curatorFramework.getData()
                    .usingWatcher((Watcher) watchedEvent -> {
                        Watcher.Event.EventType type = watchedEvent.getType();
                        processConfigEvent(type, path);
                    })
                    .forPath(path);
            return new String(bytes);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private void processConfigEvent(Watcher.Event.EventType type, String key) {
        if (Watcher.Event.EventType.NodeDataChanged == type) {
            initConfig(key);
        }
        if (Watcher.Event.EventType.NodeDeleted == type) {
            configMap.remove(key);
        }
    }
}
